package com.gitee.luosl.cola.lang;

import com.gitee.luosl.cola.lang.function.Consumer4;
import com.gitee.luosl.cola.lang.function.Function4;
import com.gitee.luosl.cola.lang.function.Predicate4;

import java.util.Objects;
import java.util.function.Function;

public final class Tuple4<T1, T2, T3, T4> implements Tuple {

    public final T1 _1;

    public final T2 _2;

    public final T3 _3;

    public final T4 _4;

    Tuple4(T1 _1, T2 _2, T3 _3, T4 _4) {
        this._1 = _1;
        this._2 = _2;
        this._3 = _3;
        this._4 = _4;
    }

    public T1 get_1() {
        return _1;
    }

    public T2 get_2() {
        return _2;
    }

    public T3 get_3() {
        return _3;
    }

    public T4 get_4() {
        return _4;
    }

    public <R> Tuple4<R, T2, T3, T4> map1(Function<? super T1, ? extends R> function){
        return Tuple.of(function.apply(_1), _2, _3, _4);
    }

    public <R> Tuple4<T1, R, T3, T4> map2(Function<? super T2, ? extends R> function){
        return Tuple.of(_1, function.apply(_2), _3, _4);
    }

    public <R> Tuple4<T1, T2, R, T4> map3(Function<? super T3, ? extends R> function){
        return Tuple.of(_1, _2, function.apply(_3), _4);
    }

    public <R> Tuple4<T1, T2, T3, R> map4(Function<? super T4, ? extends R> function){
        return Tuple.of(_1, _2, _3, function.apply(_4));
    }

    public <R> R apply(Function4<? super T1, ? super T2, ? super T3, ? super T4, ? extends R> mapper){
        return mapper.apply(_1, _2, _3, _4);
    }

    public <R1, R2, R3, R4> Tuple4<R1, R2, R3, R4> map(Function4<? super T1, ? super T2, ? super T3, ? super T4, Tuple4<R1, R2, R3, R4>> mapper){
        return apply(mapper);
    }

    public void accept(Consumer4<? super T1, ? super T2, ? super T3, ? super T4> consumer){
        consumer.accept(_1, _2, _3, _4);
    }

    public boolean test(Predicate4<? super T1, ? super T2, ? super T3, ? super T4> predicate){
        return predicate.test(_1, _2, _3, _4);
    }

    public Tuple4<T4, T3, T2, T1> reverse() {
        return Tuple.of(_4, _3, _2, _1);
    }

    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + Objects.hashCode(_1);
        result = 31 * result + Objects.hashCode(_2);
        result = 31 * result + Objects.hashCode(_3);
        result = 31 * result + Objects.hashCode(_4);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        } else if (!(obj instanceof Tuple4)) {
            return false;
        } else {
            final Tuple4<?, ?, ?, ?> that = (Tuple4<?, ?, ?, ?>) obj;
            return Objects.equals(this._1, that._1)
                    && Objects.equals(this._2, that._2)
                    && Objects.equals(this._3, that._3)
                    && Objects.equals(this._4, that._4);
        }
    }

    @Override
    public String toString() {
        return String.format(
                "(%s, %s, %s, %s)",
                Objects.toString(_1),
                Objects.toString(_2),
                Objects.toString(_3),
                Objects.toString(_4)
        );
    }
}
